{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c3bc5d25-6306-46a3-9060-cb7269b0b03e",
   "metadata": {},
   "outputs": [],
   "source": [
    "conda install pandas scikit-learn numpy matplotlib pillow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dabcb14a-cab8-44a8-8a49-8c8ad7337ad6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tkinter as tk  # tkinter library for creating user interface\n",
    "import os  # os library for file and directory operations\n",
    "import pandas as pd  # pandas library for data processing\n",
    "from sklearn.neighbors import KNeighborsClassifier  # KNeighborsClassifier from sklearn for KNN algorithm\n",
    "import numpy as np  # numpy library for numerical calculations\n",
    "import csv  # csv library for reading and writing csv files\n",
    "from PIL import Image, ImageTk  # PIL library for image processing\n",
    "import logging  # logging library for logging\n",
    "import matplotlib.pyplot as plt  # matplotlib library for data visualization\n",
    "from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg  # FigureCanvasTkAgg for displaying matplotlib figures in tkinter\n",
    "logging.basicConfig(level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')  # Set log output format and level\n",
    "\n",
    "class MovieRatingApp:  # Define movie rating application class\n",
    "    def __init__(self, root):  # Initialization method, set basic properties and interface of the application\n",
    "        self.root = root  # Set application root window\n",
    "        root.title(\"Movie Rating App\")  # Set application title\n",
    "        root.geometry(\"900x600\")  # Set application window size\n",
    "\n",
    "        # Load and display movie images (handle missing images gracefully)\n",
    "        try:\n",
    "            self.image1 = Image.open('post1_relie.jpg')  # Load movie 1 image\n",
    "            self.image1.thumbnail((100, 300))  # Set image size\n",
    "            self.movie1_image = ImageTk.PhotoImage(self.image1)  # Convert image to tkinter displayable format\n",
    "            self.movie1_label = tk.Label(root, image=self.movie1_image)  # Create label to display image\n",
    "        except:\n",
    "            self.movie1_label = tk.Label(root, text=\"Movie 1\\n(Image not found)\", width=15, height=10)\n",
    "        self.movie1_label.grid(row=0, column=0, padx=10, pady=10)  # Add label to interface\n",
    "\n",
    "        try:\n",
    "            self.image2 = Image.open(\"post2_family.jpg\")  # Load movie 2 image\n",
    "            self.image2.thumbnail((100, 300))  # Set image size\n",
    "            self.movie2_image = ImageTk.PhotoImage(self.image2)  # Convert image to tkinter displayable format\n",
    "            self.movie2_label = tk.Label(root, image=self.movie2_image)  # Create label to display image\n",
    "        except:\n",
    "            self.movie2_label = tk.Label(root, text=\"Movie 2\\n(Image not found)\", width=15, height=10)\n",
    "        self.movie2_label.grid(row=0, column=1, padx=10, pady=10)  # Add label to interface\n",
    "\n",
    "        # Create rating dropdown menus\n",
    "        self.movie1_rating = tk.StringVar(root, value=\"1\")  # Create movie 1 rating variable\n",
    "        tk.OptionMenu(root, self.movie1_rating, \"1\", \"2\", \"3\", \"4\", \"5\").grid(row=1, column=0, padx=10, pady=10)  # Create movie 1 rating dropdown\n",
    "\n",
    "        self.movie2_rating = tk.StringVar(root, value=\"1\")  # Create movie 2 rating variable\n",
    "        tk.OptionMenu(root, self.movie2_rating, \"1\", \"2\", \"3\", \"4\", \"5\").grid(row=1, column=1, padx=10, pady=10)  # Create movie 2 rating dropdown\n",
    "\n",
    "        # Create radio buttons for movie type selection\n",
    "        self.preference = tk.IntVar()  # Create movie type variable\n",
    "        tk.Radiobutton(root, text=\"Action\", variable=self.preference, value=0).grid(row=2, column=0, padx=10, pady=10)  # Create action movie radio button\n",
    "        tk.Radiobutton(root, text=\"Comedy\", variable=self.preference, value=1).grid(row=2, column=1, padx=10, pady=10)  # Create comedy movie radio button\n",
    "\n",
    "        # Create buttons\n",
    "        tk.Button(root, text=\"Confirm\", command=self.confirm).grid(row=3, column=0, padx=10, pady=20)  # Create confirm button, calls confirm method when clicked\n",
    "        tk.Button(root, text=\"Clear\", command=self.clear_plot).grid(row=3, column=1, padx=10, pady=20)  # Create clear button, calls clear_plot method when clicked\n",
    "        tk.Button(root, text=\"Predict\", command=self.predict_preference).grid(row=4, columnspan=2, padx=10, pady=20)  # Create predict button, calls predict_preference method when clicked\n",
    "        self.predict_label = tk.Label(root, text=\"\")  # Create label to display prediction result\n",
    "        self.predict_label.grid(row=5, columnspan=2, padx=10, pady=10)  # Add label to interface\n",
    "\n",
    "        self.filename = 'ratings.csv'  # Set filename for storing rating data\n",
    "\n",
    "        if not os.path.isfile(self.filename):  # If file doesn't exist\n",
    "            with open(self.filename, 'w', newline='') as file:  # Create file\n",
    "                writer = csv.writer(file)  # Create csv file writer\n",
    "                writer.writerow([\"Movie1\", \"Movie2\", \"Preference\"])  # Write header\n",
    "\n",
    "        # Create frame for displaying plot\n",
    "        self.plot_frame = tk.Frame(root)  # Create frame\n",
    "        self.plot_frame.grid(row=0, column=2, rowspan=4, padx=10, pady=10)  # Add frame to interface\n",
    "        self.plot_ratings()  # Call plot_ratings method to display rating data plot\n",
    "\n",
    "    def confirm(self):  # Define confirm method for saving user ratings and movie type selection\n",
    "        m1_rating = self.movie1_rating.get()  # Get movie 1 rating\n",
    "        m2_rating = self.movie2_rating.get()  # Get movie 2 rating\n",
    "        preference = self.preference.get()  # Get movie type selection\n",
    "\n",
    "        with open(self.filename, 'a', newline='') as file:  # Open file\n",
    "            writer = csv.writer(file)  # Create csv file writer\n",
    "            writer.writerow([m1_rating, m2_rating, preference])  # Write user ratings and movie type selection\n",
    "\n",
    "        self.plot_ratings()  # Call plot_ratings method to update rating data plot\n",
    "\n",
    "    def clear_plot(self):  # Define clear method for clearing all rating data\n",
    "        with open(self.filename, 'w', newline='') as file:  # Open file\n",
    "            writer = csv.writer(file)  # Create csv file writer\n",
    "            writer.writerow([\"Movie1\", \"Movie2\", \"Preference\"])  # Write header\n",
    "        self.predict_label.config(text=\"\")  # Clear prediction result label\n",
    "        self.plot_ratings()  # Call plot_ratings method to update rating data plot\n",
    "\n",
    "    def plot_ratings(self):  # Define method to display rating data\n",
    "        # Destroy old widgets in plot_frame\n",
    "        for widget in self.plot_frame.winfo_children():\n",
    "            widget.destroy()\n",
    "\n",
    "        df = pd.read_csv(self.filename)  # Read rating data\n",
    "        \n",
    "        # Skip header row if there's no data yet\n",
    "        if len(df) > 0:\n",
    "            action_movies = df[df['Preference'] == 0]  # Get action movie rating data\n",
    "            comedy_movies = df[df['Preference'] == 1]  # Get comedy movie rating data\n",
    "\n",
    "            fig, ax = plt.subplots(figsize=(6, 5))  # Create figure and axes\n",
    "            ax.grid(True)  # Show grid\n",
    "            \n",
    "            if len(action_movies) > 0:\n",
    "                ax.scatter(action_movies['Movie1'], action_movies['Movie2'], color='orange', label='Action', s=100)  # Plot action movie rating data\n",
    "                # Add movie coordinates to plot\n",
    "                for i in range(len(action_movies)):\n",
    "                    ax.text(action_movies['Movie1'].iloc[i], action_movies['Movie2'].iloc[i] + 0.1, \n",
    "                           f'({action_movies[\"Movie1\"].iloc[i]}, {action_movies[\"Movie2\"].iloc[i]})', fontsize=8)\n",
    "            \n",
    "            if len(comedy_movies) > 0:\n",
    "                ax.scatter(comedy_movies['Movie1'], comedy_movies['Movie2'], color='blue', label='Comedy', s=100)  # Plot comedy movie rating data\n",
    "                # Add movie coordinates to plot\n",
    "                for i in range(len(comedy_movies)):\n",
    "                    ax.text(comedy_movies['Movie1'].iloc[i], comedy_movies['Movie2'].iloc[i] + 0.1, \n",
    "                           f'({comedy_movies[\"Movie1\"].iloc[i]}, {comedy_movies[\"Movie2\"].iloc[i]})', fontsize=8)\n",
    "\n",
    "            ax.set_xlabel('Movie A Rating')  # Set x-axis label\n",
    "            ax.set_ylabel('Movie B Rating')  # Set y-axis label\n",
    "            ax.set_xlim([0, 6])  # Set x-axis range\n",
    "            ax.set_ylim([0, 6])  # Set y-axis range\n",
    "            ax.legend()  # Show legend\n",
    "\n",
    "            canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)  # Convert figure to tkinter displayable format\n",
    "            canvas.draw()  # Display figure\n",
    "            canvas.get_tk_widget().pack()  # Add figure to frame\n",
    "        else:\n",
    "            # Display message when no data\n",
    "            no_data_label = tk.Label(self.plot_frame, text=\"No rating data available\\nPlease add ratings using Confirm button\")\n",
    "            no_data_label.pack(padx=10, pady=10)\n",
    "\n",
    "    def predict_preference(self):  # Define prediction method for predicting user's preferred movie type\n",
    "        df = pd.read_csv(self.filename)  # Read rating data\n",
    "        \n",
    "        # Check if there's enough data for prediction\n",
    "        if len(df) < 1:\n",
    "            self.predict_label.config(text=\"Not enough data for prediction. Please add some ratings first.\")\n",
    "            return\n",
    "            \n",
    "        X = df[['Movie1', 'Movie2']].values  # Get all rating data from CSV file\n",
    "        y = df['Preference'].values  # Get all movie type selections from CSV file\n",
    "\n",
    "        knn = KNeighborsClassifier(n_neighbors=1)  # Create KNN classifier with K=1\n",
    "        knn.fit(X, y)  # Train the classifier\n",
    "\n",
    "        m1_rating = int(self.movie1_rating.get())  # Get new user's movie 1 rating\n",
    "        m2_rating = int(self.movie2_rating.get())  # Get new user's movie 2 rating\n",
    "        \n",
    "        new_point = np.array([[m1_rating, m2_rating]])  # Create new data point for prediction\n",
    "\n",
    "        prediction = knn.predict(new_point)  # Use KNN to predict movie type for new data point, 0 for action, 1 for comedy\n",
    "        \n",
    "        self.predict_label.config(text=f\"Recommended movie type for user: {'Action' if prediction[0] == 0 else 'Comedy'}\")  # Display prediction result\n",
    "\n",
    "        # Get current figure to add prediction visualization\n",
    "        df = pd.read_csv(self.filename)\n",
    "        if len(df) > 0:\n",
    "            fig, ax = plt.subplots(figsize=(6, 5))\n",
    "            ax.grid(True)\n",
    "            \n",
    "            action_movies = df[df['Preference'] == 0]\n",
    "            comedy_movies = df[df['Preference'] == 1]\n",
    "            \n",
    "            if len(action_movies) > 0:\n",
    "                ax.scatter(action_movies['Movie1'], action_movies['Movie2'], color='orange', label='Action', s=100)\n",
    "            if len(comedy_movies) > 0:\n",
    "                ax.scatter(comedy_movies['Movie1'], comedy_movies['Movie2'], color='blue', label='Comedy', s=100)\n",
    "            \n",
    "            # Plot new point and connection line\n",
    "            ax.scatter(new_point[:, 0], new_point[:, 1], color='red', marker='x', s=100, label='New User')\n",
    "            distances, indices = knn.kneighbors(new_point)  # Get distance matrix and index matrix for nearest neighbors\n",
    "            nearest_neighbor = X[indices[0][0]]  # Get coordinates of nearest neighbor\n",
    "            \n",
    "            # Draw connection line\n",
    "            ax.plot([new_point[0, 0], nearest_neighbor[0]], [new_point[0, 1], nearest_neighbor[1]], 'r--', linewidth=2)\n",
    "            \n",
    "            # Add coordinate labels\n",
    "            for i in range(len(df)):\n",
    "                ax.text(df['Movie1'].iloc[i], df['Movie2'].iloc[i] + 0.1, \n",
    "                       f'({df[\"Movie1\"].iloc[i]}, {df[\"Movie2\"].iloc[i]})', fontsize=8)\n",
    "            ax.text(new_point[0, 0], new_point[0, 1] + 0.1, \n",
    "                   f'({new_point[0, 0]}, {new_point[0, 1]})', fontsize=8, color='red')\n",
    "            \n",
    "            ax.set_xlabel('Movie A Rating')\n",
    "            ax.set_ylabel('Movie B Rating')\n",
    "            ax.set_xlim([0, 6])\n",
    "            ax.set_ylim([0, 6])\n",
    "            ax.legend()\n",
    "            \n",
    "            # Update the plot frame\n",
    "            for widget in self.plot_frame.winfo_children():\n",
    "                widget.destroy()\n",
    "                \n",
    "            canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)\n",
    "            canvas.draw()\n",
    "            canvas.get_tk_widget().pack()\n",
    "\n",
    "root = tk.Tk()  # Create tkinter root window\n",
    "app = MovieRatingApp(root)  # Create movie rating application\n",
    "root.mainloop()  # Start application"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b1abcb2d-829e-4945-88f0-35ef9d39b693",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "movie_env",
   "language": "python",
   "name": "movie_env"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
